package com.example.sparkchaindemo.service;

import android.Manifest;
import android.app.NotificationChannel;
import android.app.NotificationManager;
import android.app.Service;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.media.AudioFormat;
import android.media.AudioRecord;
import android.media.MediaRecorder;
import android.os.Binder;
import android.os.Build;
import android.os.Handler;
import android.os.IBinder;
import android.os.Looper;
import android.os.Message;
import android.text.TextUtils;
import android.util.Log;
import android.widget.Toast;

import androidx.annotation.NonNull;
import androidx.core.app.ActivityCompat;
import androidx.core.app.NotificationCompat;

import com.example.sparkchaindemo.IVWActivity;
import com.example.sparkchaindemo.R;
import com.example.sparkchaindemo.RTASRActivity;
import com.example.sparkchaindemo.app.SparkHelper;
import com.example.sparkchaindemo.utils.SparkUtils;
import com.iflytek.aikit.core.AiAudio;
import com.iflytek.aikit.core.AiHandle;
import com.iflytek.aikit.core.AiHelper;
import com.iflytek.aikit.core.AiListener;
import com.iflytek.aikit.core.AiRequest;
import com.iflytek.aikit.core.AiResponse;
import com.iflytek.aikit.core.AiStatus;
import com.iflytek.aikit.core.CoreListener;
import com.iflytek.aikit.core.ErrType;
import com.iflytek.sparkchain.core.rtasr.RTASR;
import com.iflytek.sparkchain.core.rtasr.RTASRCallbacks;

import java.io.BufferedWriter;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.nio.charset.StandardCharsets;
import java.util.List;
import java.util.concurrent.atomic.AtomicBoolean;

/**
 * 讯飞语音唤醒
 */
public class SparkService extends Service {
    Context mContext;
    private static final String ABILITYID = "e867a88f2";
    private static final int START = 0x0001;
    private static final int WRITE_BY_RECORDING = 0x0002;
    private static final int END = 0x0004;
    private AudioRecord audioRecord = null;
    private AtomicBoolean isEnd = new AtomicBoolean(true);
    private AtomicBoolean isStartRecord = new AtomicBoolean(false);
    private AtomicBoolean isStart = new AtomicBoolean(false);
    private AtomicBoolean isTimerRunning = new AtomicBoolean(false);
    //录音缓冲区大小
    private final int BUFFER_SIZE = 1280;
    //录音是否在进行
    private AtomicBoolean isRecording = new AtomicBoolean(false);
    private final String TAG = "SparkService";
    private AiHandle aiHandle;
    private String RES_DIR;
    private Handler aiKitHandler;
    private RTASR mRTASR;
    private String RTASRAPIKEY = "";
    boolean isrun = false;
    String asrFinalResult = "";
    private Handler mainHandler;


//    private final Handler mHandler = new Handler(Looper.myLooper()) {
//        @Override
//        public void handleMessage(@NonNull Message msg) {
//            super.handleMessage(msg);
//            switch (msg.what) {
//                case 1:
//                    Toast.makeText(getApplicationContext(), "获取机器信息成功", Toast.LENGTH_SHORT).show();
//                    break;
//                case 2:
//                    Toast.makeText(getApplicationContext(), "获取机器信息失败", Toast.LENGTH_SHORT).show();
//                    break;
//                case 3:
//                    Log.e("ErrorMsgService", "handleMessage: wifi变化 重新登录");
//                    Intent intent1 = new Intent();
//                    intent1.setAction("Finish");
//                    sendBroadcast(intent1);
////                    LiveEventBus.get("relogin").post(true);
//
//                    Intent intent2 = new Intent();
    /// /                    intent2.setClass(mContext, LoginActivity.class);
//                    intent2.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
//                    startActivity(intent2);
//
//                    stopForeground(true);
//                    stopSelf();
//                    break;
//                case 104:
//                    Intent intent22 = new Intent();
//                    intent22.setAction("login_re");
//                    sendBroadcast(intent22);
//                    stopForeground(true);
//                    stopSelf();
//                    break;
//            }
//        }
//    };

    private final IBinder binder = new LocalBinder();

    public class LocalBinder extends Binder {
        public SparkService getService() {
            return SparkService.this;
        }
    }

    @Override
    public IBinder onBind(Intent intent) {
        return binder;
    }

    @Override
    public void onCreate() {
        super.onCreate();
        this.mContext = this;
        mainHandler = new Handler(Looper.getMainLooper());

        // Create notification channel for Android O and above
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            NotificationChannel channel = new NotificationChannel(
                    "error_msg_service",
                    "Error Message Service",
                    NotificationManager.IMPORTANCE_DEFAULT
            );
            channel.setDescription("ROS Bridge Service Notification");
            channel.enableLights(true);
            channel.enableVibration(true);
            NotificationManager manager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
            manager.createNotificationChannel(channel);
        }

        // Create and start foreground notification
        NotificationCompat.Builder builder = new NotificationCompat.Builder(this, "error_msg_service")
                .setContentTitle("ROS Bridge Service")
                .setContentText("Service is running")
                .setSmallIcon(R.mipmap.ic_launcher)  // 使用应用图标
                .setPriority(NotificationCompat.PRIORITY_DEFAULT)
                .setOngoing(true)  // 设置为持续通知
                .setAutoCancel(false);  // 禁止滑动清除

        startForeground(3, builder.build());

        startInit();
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        // Return START_STICKY to ensure the service is restarted if killed
        return START_STICKY;
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        stop();
    }

    private void startInit() {
        AiHelper.getInst().registerListener(ABILITYID, edListener);
        RES_DIR = getFilesDir().getAbsolutePath() + "/ivw";
        mThread.start();

        initSDK();
        initRtasr();
    }

    private void initRtasr() {
        RTASRAPIKEY = getResources().getString(R.string.RTASRAPIKEY);
        mRTASR = new RTASR(RTASRAPIKEY);//创建RTASR实例
        mRTASR.registerCallbacks(mRtAsrCallbacks);//注册监听回调
    }

    private void initSDK() {
        SparkUtils.initAiKitSDK(getApplication(), new CoreListener() {
            @Override
            public void onAuthStateChange(final ErrType type, final int code) {
                Log.i(TAG, "core listener code:" + code);
                Intent intent = new Intent();
                intent.setAction("initAiKitSDK");
                sendBroadcast(intent);
                //录音监听中
                startListen();
            }
        });
    }

    private void stop() {
        if (audioRecord != null) {

            Intent stopRecordIntent = new Intent();
            stopRecordIntent.setAction("stopRecord");
            sendBroadcast(stopRecordIntent);

            audioRecord.stop();
            isRecording.set(false);
        }
        stopListen();
        end();
        audioRecord = null;
        AiHelper.getInst().unInit();
        stopRtast();
    }

    private final Thread mThread = new Thread(new Runnable() {
        @Override
        public void run() {
            Looper.prepare();
            aiKitHandler = new Handler(Looper.myLooper()) {

                @Override
                public void handleMessage(@NonNull Message msg) {
                    super.handleMessage(msg);
                    switch (msg.what) {
                        case START:
                            /**
                             * 开始会话
                             */
                            Log.d(TAG, "START");
                            int ret = start();
                            if (ret == 0) {
                                int type = msg.arg1;
                                if (type == WRITE_BY_RECORDING) {
                                    createAudioRecord();//创建录音器
                                    isRecording.set(true);
                                    Intent intent = new Intent();
                                    intent.setAction("startRecord");
                                    sendBroadcast(intent);
                                    audioRecord.startRecording();//录音器启动录音
                                }
                                aiKitHandler.removeCallbacksAndMessages(null);//清空消息队列
                                Message write_msg = new Message();
                                write_msg.what = type;
                                write_msg.obj = AiStatus.BEGIN;
                                aiKitHandler.sendMessage(write_msg);//调用write方法送音频数据给引擎
                            }
                            break;
                        case WRITE_BY_RECORDING:
                            /**
                             * 写入数据-录音方式
                             */
                            AiStatus status = (AiStatus) msg.obj;
                            byte data[] = new byte[BUFFER_SIZE];
                            int read = audioRecord.read(data, 0, BUFFER_SIZE);
                            //平方和除以数据总长度，得到音量大小。
                            Intent intent = new Intent();
                            intent.setAction("calculateVolume");
                            final int volume = calculateVolume(data);
                            intent.putExtra("volume", volume);
                            sendBroadcast(intent);

                            if (AudioRecord.ERROR_INVALID_OPERATION != read) {
                                //处理录音数据
                                write(data, status);//送尾帧
                            }
                            if (AiStatus.END == status) {
                                if (audioRecord != null) {
                                    Intent stopRecordIntent = new Intent();
                                    stopRecordIntent.setAction("stopRecord");
                                    sendBroadcast(stopRecordIntent);

                                    audioRecord.stop();
                                    isRecording.set(false);

                                    Intent volumeIntent = new Intent();
                                    volumeIntent.setAction("calculateVolume");
                                    volumeIntent.putExtra("volume", 0);
                                    sendBroadcast(volumeIntent);

                                    aiKitHandler.sendEmptyMessage(END);
                                }
                            } else {
                                if (isRecording.get()) {
                                    Message write_msg = new Message();
                                    write_msg.what = WRITE_BY_RECORDING;
                                    write_msg.obj = AiStatus.CONTINUE;
                                    aiKitHandler.sendMessage(write_msg);//调用write方法送音频数据给引擎
                                }
                            }
                            break;
                        case END:
                            /**
                             * 结束会话
                             */
                            Log.d(TAG, "END");
                            end();
                            break;
                    }
                }
            };
            Looper.loop();
        }
    });

    private void createAudioRecord() {
        if (isRecording.get()) {
            return;
        }
        if (audioRecord == null) {
            Log.d(TAG, "createAudioRecord");
            if (ActivityCompat.checkSelfPermission(this, Manifest.permission.RECORD_AUDIO) != PackageManager.PERMISSION_GRANTED) {
                // TODO: Consider calling
                //    ActivityCompat#requestPermissions
                // here to request the missing permissions, and then overriding
                //   public void onRequestPermissionsResult(int requestCode, String[] permissions,
                //                                          int[] grantResults)
                // to handle the case where the user grants the permission. See the documentation
                // for ActivityCompat#requestPermissions for more details.
                return;
            }
            audioRecord = new AudioRecord(MediaRecorder.AudioSource.MIC,
                    16000,
                    AudioFormat.CHANNEL_IN_MONO,
                    AudioFormat.ENCODING_PCM_16BIT,
                    BUFFER_SIZE);
        }
    }

    /**
     * 能力监听回调
     */
    private final AiListener edListener = new AiListener() {
        @Override
        public void onResult(int handleID, List<AiResponse> outputData, Object usrContext) {
            if (isTimerRunning.get()) {
                return;
            }
            if (null != outputData && !outputData.isEmpty()) {//唤醒一次成功
                runRtasr_Audio();

                Intent volumeIntent = new Intent();
                volumeIntent.setAction("callSuccess");
                sendBroadcast(volumeIntent);

                Log.i(TAG, "onResult:handleID:" + handleID + ":" + outputData.size() + "," +
                        "usrContext:" + usrContext);
                for (int i = 0; i < outputData.size(); i++) {
                    Log.d(TAG, "onResult:handleID:" + handleID + ":" + outputData.get(i).getKey());
                    String key = outputData.get(i).getKey();   //引擎结果的key
                    byte[] bytes = outputData.get(i).getValue(); //识别结果
                    String result = new String(bytes);
                    Log.d(TAG, "key=" + key);
                    Log.d(TAG, "value=" + result);
                    Log.d(TAG, "status=" + outputData.get(i).getStatus());
                    if ((key.equals("func_wake_up") || key.equals("func_pre_wakeup"))) {
//                        showInfo(key + ": \n " + result);
                    }
                }
            }
        }

        @Override
        public void onEvent(int i, int i1, List<AiResponse> list, Object o) {
            Log.i(TAG, "onEvent:" + i + ",event:" + i1);

        }

        @Override
        public void onError(int i, int i1, String s, Object o) {
//            showInfo("错误通知，能力执行终止,Ability " + i + " ERROR::" + s + ",err code:" + i1);
        }
    };

    /**
     * 开始会话
     */
    private int start() {
        if (!keyword2File()) {
            Toast.makeText(getApplicationContext(), "唤醒词文件写入失败，请检查是否有读写权限。", Toast.LENGTH_SHORT).show();
            return -1;
        }
        AiRequest.Builder customBuilder = AiRequest.builder();
        customBuilder.customText("key_word", RES_DIR + "/keyword.txt", 0);
        int ret = AiHelper.getInst().loadData(ABILITYID, customBuilder.build());
        if (ret != 0) {
            Toast.makeText(getApplicationContext(), "open ivw loadData 失败：" + ret, Toast.LENGTH_SHORT).show();
            return ret;
        }
        Toast.makeText(getApplicationContext(), "open ivw loadData  success：" + ret, Toast.LENGTH_SHORT).show();
        int[] indexs = {0};
        ret = AiHelper.getInst().specifyDataSet(ABILITYID, "key_word", indexs);//从缓存中把个性化资源设置到引擎中
        if (ret != 0) {
            Toast.makeText(getApplicationContext(), "open ivw specifyDataSet 失败：" + ret, Toast.LENGTH_SHORT).show();
            return ret;
        }
        Toast.makeText(getApplicationContext(), "open ivw specifyDataSet  success：" + ret, Toast.LENGTH_SHORT).show();

        AiRequest.Builder paramBuilder = AiRequest.builder();
        paramBuilder.param("wdec_param_nCmThreshold", "0 0:800");
        paramBuilder.param("gramLoad", true);
        isEnd.set(false);
        aiHandle = AiHelper.getInst().start(ABILITYID, paramBuilder.build(), null);
        if (aiHandle.getCode() != 0) {
            Toast.makeText(getApplicationContext(), "open ivw start失败：" + aiHandle.getCode(), Toast.LENGTH_SHORT).show();
            return aiHandle.getCode();
        }
        return 0;
    }

    /**
     * 写入数据
     */
    private void write(byte[] part, AiStatus status) {
        if (isEnd.get()) {
            return;
        }
        AiRequest.Builder dataBuilder = AiRequest.builder();
        int ret = 0;

        /**
         * 送入音频需要标识音频的状态，第一帧为起始帧，status要传AiStatus.BEGIN,最后一帧为结束帧，status要传AiStatus.END,其他为中间帧，status要传AiStatus.CONTINUE
         * 音频要求16bit，16K，单声道的pcm音频。
         * 建议每次发送音频间隔40ms，每次发送音频字节数为一帧音频大小的整数倍。
         */
        AiAudio aiAudio = AiAudio.get("wav").data(part).status(status).valid();
        dataBuilder.payload(aiAudio);

        ret = AiHelper.getInst().write(dataBuilder.build(), aiHandle);
        if (ret != 0) {
            Toast.makeText(getApplicationContext(), "write失败：" + ret + " ", Toast.LENGTH_SHORT).show();
        }
    }

    private boolean keyword2File() {
        try {
            // 确保目录存在
            File dir = new File(RES_DIR);
            if (!dir.exists()) {
                dir.mkdirs();
            }
            File keywordFile = new File(RES_DIR + "/keyword.txt");
            if (keywordFile.exists()) {
                //强制清空内容
                keywordFile.delete();
            }
            File binFile = new File(RES_DIR + "/keyword.bin");
            if (binFile.exists()) {
                binFile.delete();
            }
            String keyword = SparkHelper.getInstance().getKeyword();
            if (TextUtils.isEmpty(keyword)) {
                keyword = "你好小迪";
            }
            String str = keyword.replace("，", ",");
            String[] keywords = str.split(",");
            if (!keywordFile.exists()) {
                keywordFile.createNewFile();
            }
            OutputStreamWriter writer = new OutputStreamWriter(new FileOutputStream(keywordFile),
                    StandardCharsets.UTF_8);
            BufferedWriter bufferedWriter = new BufferedWriter(writer);
            for (int i = 0; i < keywords.length; i++) {
                bufferedWriter.write(keywords[i]);
                bufferedWriter.write(";");
                bufferedWriter.newLine();//写入换行
            }
            bufferedWriter.close();
        } catch (IOException e) {
            e.printStackTrace();
            return false;
        }
        return true;
    }

    /**
     * 结束会话
     */
    private void end() {
        if (!isEnd.get()) {
            int ret = AiHelper.getInst().end(aiHandle);
            if (ret == 0) {
                isEnd.set(true);
                aiHandle = null;
//                showInfo("唤醒完成，end： " + ret);
            } else {
                isEnd.set(false);
//                showInfo("唤醒完成，end： " + ret);
            }
        }
    }

    /**
     * 根据录音数据计算音量
     */
    private int calculateVolume(byte[] buffer) {
        double sumVolume = 0.0;
        double avgVolume = 0.0;
        int volume = 0;
        for (int i = 0; i < buffer.length; i += 2) {
            int v1 = buffer[i] & 0xFF;
            int v2 = buffer[i + 1] & 0xFF;
            int temp = v1 + (v2 << 8);// 小端
            if (temp >= 0x8000) {
                temp = 0xffff - temp;
            }
            sumVolume += Math.abs(temp);
        }
        avgVolume = sumVolume / buffer.length / 2;
        volume = (int) (Math.log10(1 + avgVolume) * 10);
        return volume;
    }

    /**
     * 停止唤醒状态的监听
     */
    public void stopListen() {
        if (isStart.get()) {
            Log.e(TAG, "stop recording");
            Message msg = new Message();
            msg.what = WRITE_BY_RECORDING;
            msg.obj = AiStatus.END;
            aiKitHandler.sendMessage(msg);
        }
        AiHelper.getInst().unInit();
    }

    /**
     * 开启唤醒状态的监听
     */
    public void startListen() {
        Log.e(TAG, "start recording");
        isStartRecord.set(false);
        Message msg = new Message();
        msg.what = START;
        msg.arg1 = WRITE_BY_RECORDING;
        aiKitHandler.sendMessage(msg);
    }

    /**
     * 语音实时识别回调
     */
    private final RTASRCallbacks mRtAsrCallbacks = new RTASRCallbacks() {
        @Override
        public void onResult(RTASR.RtAsrResult result, Object usrTag) {
            String data = result.getData();
            String rawResult = result.getRawResult();
            int status = result.getStatus();
            String sid = result.getSid();
            String src = result.getTransResult().getSrc();
            String dst = result.getTransResult().getDst();

            if (status == 1) {
                String asrText = asrFinalResult + data;
//                Intent rtasrCallIntent = new Intent();
//                rtasrCallIntent.setAction("rtasrCall");
//                rtasrCallIntent.putExtra("content", asrText);
//                sendBroadcast(rtasrCallIntent);

            } else if (status == 2) {
                asrFinalResult = asrFinalResult + data;

                Intent rtasrCallIntent = new Intent();
                rtasrCallIntent.setAction("rtasrCall");
                rtasrCallIntent.putExtra("content", asrFinalResult);
                sendBroadcast(rtasrCallIntent);

                if (!isTimerRunning.get()) {
                    isTimerRunning.set(true);
                    mainHandler.postDelayed(new Runnable() {
                        @Override
                        public void run() {
                            if (isrun) {
                                if (mRTASR != null) {
                                    mRTASR.stopListener();
                                    mRTASR = null;
                                }
                                isrun = false;
                            }
                            isTimerRunning.set(false);
                        }
                    }, 2000);
                }
            } else if (status == 3) {
                Intent rtasrCallFinishedIntent = new Intent();
                rtasrCallFinishedIntent.setAction("rtasrCallFinished");
                sendBroadcast(rtasrCallFinishedIntent);
            }
        }

        @Override
        public void onError(RTASR.RtAsrError error, Object usrTag) {
            int code = error.getCode();
            String msg = error.getErrMsg();
            String sid = error.getSid();
            Log.e(TAG, "RTASR onError: code=" + code + ", msg=" + msg + ", sid=" + sid);
            stopRtast();
        }

        @Override
        public void onBeginOfSpeech() {
//            runOnUiThread(new Runnable() {
//                @Override
//                public void run() {
//                    Log.d(TAG, "onBeginOfSpeech");
//                    tv_statusInfo.setText("检测到语音开始");
//                }
//            });
        }

        @Override
        public void onEndOfSpeech() {
//            runOnUiThread(new Runnable() {
//                @Override
//                public void run() {
//                    Log.d(TAG, "onEndOfSpeech");
//                    tv_statusInfo.setText("检测到语音结束，处理中...");
//                    // SDK会自动发送结束帧，通常不需要手动stopListener，除非用户点击停止按钮
//                }
//            });
        }
    };

    int count = 0;//用户自定义标识

    private void runRtasr_Audio() {
        if (isrun) return; // 再次检查，防止并发问题
        asrFinalResult = "";
        count++;
        isrun = true;
        if (mRTASR == null) {
            mRTASR = new RTASR(RTASRAPIKEY);
            mRTASR.registerCallbacks(mRtAsrCallbacks);
        }

        mRTASR.transType("normal");
        mRTASR.transStrategy(2);

        mRTASR.lang("cn");
        mRTASR.targetLang("en");

        Intent stopRecordIntent = new Intent();
        stopRecordIntent.setAction("recording");
        sendBroadcast(stopRecordIntent);

        int ret = mRTASR.startListener(count + "");
        Log.d(TAG, "mRTASR.startListener ret:" + ret + "-count:" + count);
        if (ret != 0) {
            isrun = false;
            Intent recordErrorIntent = new Intent();
            recordErrorIntent.setAction("recordErrorIntent");
            sendBroadcast(recordErrorIntent);
        }
    }

    public void stopRtast() {
        new Thread(new Runnable() {
            @Override
            public void run() {
                if (mRTASR != null && isrun) {
                    mRTASR.stopListener();
                    isrun = false;
                    mRTASR = null;
                }
            }
        }).start();
    }

    private enum ASRMode {
        CN,
        EN
    }

}
